#include "AoiDetPlusRsp.h"
#include <QList>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
#include "Configer.h"

using namespace aoi;

InferenceTime::InferenceTime()
{
}

InferenceTime::InferenceTime(float all, float postAI, float stream)
{
	this->all = all;
	this->postAI = postAI;
	this->stream = stream;
}

RspStausInfo::RspStausInfo()
{
}

RspStausInfo::RspStausInfo(QString errorCode, QString errorMsg, bool isSuccess, InferenceTime inferenceTime)
{
	this->errorCode = errorCode;
	this->errorMsg = errorMsg;
	this->isSuccess = isSuccess;
	this->inferenceTime = inferenceTime;
}

DetPlusBase::DetPlusBase()
{
}

DetPlusBase::DetPlusBase(QString label, float score, Box detBox)
{
	this->label = label;
	this->score = score;
	this->detBox = detBox;
}

DetPlusDetClassification::DetPlusDetClassification()
{
}

DetPlusDetClassification::DetPlusDetClassification(QString label, float score, Box detBox, Classification classification)
{
	this->label = label;
	this->score = score;
	this->detBox = detBox;
	this->classification = classification;
}

DetPlusOcr::DetPlusOcr()
{
}

DetPlusOcr::DetPlusOcr(QString label, float score, Box detBox, Ocr ocr)
{
	this->label = label;
	this->score = score;
	this->detBox = detBox;
	this->ocr = ocr;
}

DetPlusSeg::DetPlusSeg()
{
}

DetPlusSeg::DetPlusSeg(QString label, float score, Box detBox, Segmentation segmentation)
{
	this->label = label;
	this->score = score;
	this->detBox = detBox;
	this->segmentation = segmentation;
}

Segmentation::Segmentation()
{
}

Segmentation::Segmentation(QString codeType, QString mask, float score, QMap<QString, QString> labelMap, Box segBox)
{
	this->codeType = codeType;
	this->mask = mask;
	this->score = score;
	this->labelMap = labelMap;
	this->segBox = segBox;
}

Classification::Classification()
{
}

Classification::Classification(QString label, float score, Box clsBox)
{
	this->label = label;
	this->score = score;
	this->clsBox = clsBox;
}

Ocr::Ocr()
{
}

Ocr::Ocr(QString ocrText, Quad quad)
{
	this->ocrText = ocrText;
	this->quad = quad;
}

Quad::Quad()
{
}

Quad::Quad(Point topLeft, Point topRight, Point bottomLeft, Point bottomRight)
{
	this->topLeft = topLeft;
	this->topRight = topRight;
	this->bottomLeft = bottomLeft;
	this->bottomRight = bottomRight;
}

Point::Point()
{
}

Point::Point(int X, int Y)
{
	this->X = X;
	this->Y = Y;
}

Box::Box()
{
}

Box::Box(int X, int Y, int width, int height)
{
	this->X = X;
	this->Y = Y;
	this->height = height;
	this->width = width;
}

Box::Box(int X, int Y, int width, int height, float angle)
{
	this->X = X;
	this->Y = Y;
	this->height = height;
	this->width = width;
	this->angle = angle;
}

DetPlusRspParser::DetPlusRspParser()
{
}

DetPlusRspParser::DetPlusRspParser(SceneTag sceneTag)
{
	this->sceneTag = sceneTag;
}


void DetPlusRspParser::parseDetOcrList(QJsonArray& resultArray, QList<DetPlusOcr>& detPlusOcrList, int listLen)
{
	qInfo() << "===== strat parseDetOcrList =====";
	for (int i = 0; i < listLen; i++)
	{
		DetPlusOcr detPlusOcr;
		QJsonObject detPlusOcrObj = resultArray[i].toObject();
		detPlusOcr.label = detPlusOcrObj.value("Label").toString();
		detPlusOcr.score = detPlusOcrObj.value("Score").toDouble();
		QJsonObject detBoxObj = detPlusOcrObj.value("Box").toObject();
		detPlusOcr.detBox.X = detBoxObj.value("X").toDouble();
		detPlusOcr.detBox.Y = detBoxObj.value("Y").toDouble();
		detPlusOcr.detBox.width = detBoxObj.value("Width").toDouble();
		detPlusOcr.detBox.height = detBoxObj.value("Height").toDouble();
		detPlusOcr.detBox.angle = detBoxObj.value("Angle").toDouble();
		QJsonObject ocrObj = detPlusOcrObj.value("OCR").toObject();
		detPlusOcr.ocr.ocrText = ocrObj.value("OCRText").toString();
		detPlusOcr.ocr.score = ocrObj.value("Score").toDouble();
		QJsonObject quadObj = ocrObj.value("Quad").toObject();
		QJsonObject topLeftObj = quadObj.value("TopLeft").toObject();
		detPlusOcr.ocr.quad.topLeft.X = topLeftObj.value("X").toDouble();
		detPlusOcr.ocr.quad.topLeft.Y = topLeftObj.value("Y").toDouble();
		QJsonObject topRight = quadObj.value("TopRight").toObject();
		detPlusOcr.ocr.quad.topRight.X = topRight.value("X").toDouble();
		detPlusOcr.ocr.quad.topRight.Y = topRight.value("Y").toDouble();
		QJsonObject bottomLeftObj = quadObj.value("BottomLeft").toObject();
		detPlusOcr.ocr.quad.bottomLeft.X = bottomLeftObj.value("X").toDouble();
		detPlusOcr.ocr.quad.bottomLeft.Y = bottomLeftObj.value("Y").toDouble();
		QJsonObject bottomRightObj = quadObj.value("BottomRight").toObject();
		detPlusOcr.ocr.quad.bottomRight.X = bottomRightObj.value("X").toDouble();
		detPlusOcr.ocr.quad.bottomRight.Y = bottomRightObj.value("Y").toDouble();
		detPlusOcrList.append(detPlusOcr);
	}
	qInfo() << "===== end parseDetOcrList =====";
}

void DetPlusRspParser::parseDetDetClsList(QJsonArray& resultArray, QList<DetPlusDetClassification>& detPlusDetList, int listLen)
{
	qInfo() << "===== strat parseDetDetClsList =====";
	for (int i = 0; i < listLen; i++)
	{
		DetPlusDetClassification detPlusDetCls;
		QJsonObject detPlusDetObj = resultArray[i].toObject();
		detPlusDetCls.label = detPlusDetObj.value("Label").toString();
		detPlusDetCls.score = detPlusDetObj.value("Score").toDouble();
		QJsonObject detBoxObj = detPlusDetObj.value("Box").toObject();
		detPlusDetCls.detBox.X = detBoxObj.value("X").toDouble();
		detPlusDetCls.detBox.Y = detBoxObj.value("Y").toDouble();
		detPlusDetCls.detBox.width = detBoxObj.value("Width").toDouble();
		detPlusDetCls.detBox.height = detBoxObj.value("Height").toDouble();
		detPlusDetCls.detBox.angle = detBoxObj.value("Angle").toDouble();

		QJsonObject detObj = detPlusDetObj.value("Classification").toObject();
		detPlusDetCls.classification.label = detObj.value("Label").toString();
		detPlusDetCls.classification.score = detObj.value("Score").toDouble();
		QJsonObject clsBoxObj = detObj.value("Box").toObject();
		detPlusDetCls.classification.clsBox.X = clsBoxObj.value("X").toDouble();
		detPlusDetCls.classification.clsBox.Y = clsBoxObj.value("Y").toDouble();
		detPlusDetCls.classification.clsBox.width = clsBoxObj.value("Width").toDouble();
		detPlusDetCls.classification.clsBox.height = clsBoxObj.value("Height").toDouble();
		detPlusDetCls.classification.clsBox.angle = clsBoxObj.value("Angle").toDouble();
		detPlusDetList.append(detPlusDetCls);
	}

	qInfo() << "===== end parseDetDetClsList =====";
}

void DetPlusRspParser::parseDetSegList(QJsonArray& resultArray, QList<DetPlusSeg>& detPlusSegList, int listLen)
{
	qInfo() << "===== strat parseDetSegList =====";
	for (int i = 0; i < listLen; i++)
	{
		DetPlusSeg detPlusSeg;
		QJsonObject detPlusOcrObj = resultArray[i].toObject();
		detPlusSeg.label = detPlusOcrObj.value("Label").toString();
		detPlusSeg.score = detPlusOcrObj.value("Score").toDouble();
		QJsonObject detBoxObj = detPlusOcrObj.value("Box").toObject();
		detPlusSeg.detBox.X = detBoxObj.value("X").toDouble();
		detPlusSeg.detBox.Y = detBoxObj.value("Y").toDouble();
		detPlusSeg.detBox.width = detBoxObj.value("Width").toDouble();
		detPlusSeg.detBox.height = detBoxObj.value("Height").toDouble();
		detPlusSeg.detBox.angle = detBoxObj.value("Angle").toDouble();
		
		QJsonObject segObj = detPlusOcrObj.value("Segmentation").toObject();
		detPlusSeg.segmentation.codeType = segObj.value("CodeType").toString();
		detPlusSeg.segmentation.mask = segObj.value("Mask").toString();
		detPlusSeg.segmentation.score = segObj.value("Score").toDouble();
		QJsonObject segBoxObj = segObj.value("Box").toObject();
		detPlusSeg.segmentation.segBox.X= segBoxObj.value("X").toDouble();
		detPlusSeg.segmentation.segBox.Y= segBoxObj.value("Y").toDouble();
		detPlusSeg.segmentation.segBox.width= segBoxObj.value("Width").toDouble();
		detPlusSeg.segmentation.segBox.height= segBoxObj.value("Height").toDouble();
		QJsonObject labelMapObj = segObj.value("LabelMap").toObject();
		QVariantMap tmp = labelMapObj.toVariantMap();
		QMapIterator<QString, QVariant> iter(tmp);
		while (iter.hasNext()) 
		{
			iter.next();
			if (iter.value().type() == QVariant::String) 
			{
				detPlusSeg.segmentation.labelMap.insert(iter.key(), iter.value().toString());
			}
		}
		detPlusSegList.append(detPlusSeg);
	}
	qInfo() << "===== end parseDetSegList =====";
}

/*
* parse Det + Cls/Ocr/Seg Object from RspJson
*/
int DetPlusRspParser::parseDetPlusOtherRsp(QStringList fileNames, QString rspJson, DetPlusRsp& detPlusRsp)
{
	int retCode;
	QJsonParseError jsonError;
	RspStausInfo& rspStatus = detPlusRsp.rspStatus;

	QJsonDocument jsonDoc = QJsonDocument::fromJson(rspJson.toLocal8Bit().constData(), &jsonError);
	if (jsonError.error != QJsonParseError::NoError)
	{
		qCritical() << "Json ParseError:" << jsonError.errorString();
		rspStatus.errorCode = "0004";
		rspStatus.errorMsg = "json parse error: rsp json string is not correct";
		return -1;
	}
	if (jsonDoc.isNull())
	{
		qCritical() << "Rsp Json is Null.";
		rspStatus.errorCode = "0004";
		rspStatus.errorMsg = "rsp json is null";
		return -1;
	}
	QJsonObject rootObj = jsonDoc.object();

	// get all pic file infering result
	for each (QString fileName in fileNames)
	{
		QJsonArray resultArray = rootObj.value(fileName).toArray();
		if (resultArray.isEmpty())
		{
			continue;
		}

		int len = resultArray.size();
		if (len < 2)
		{
			qCritical() << fileName << ":infer result is not correct!";
			rspStatus.errorCode = "0004";
			rspStatus.errorMsg = fileName + ":infer result is not correct.";
			return -1;
		}

		// parse RegisterMatrix: rsp maybe do not have RegisterMatrix
		int listLen = 0;
		QJsonObject registerMatrixbj = resultArray[len - 2].toObject();
		if (registerMatrixbj.contains("RegisterMatrix")) 
		{
			listLen = len - 2;
		}
		else
		{
			listLen = len - 1;
		}

		// parse RspStaus info
		QJsonObject rspStausObj = resultArray[len - 1].toObject();
		rspStatus.errorCode = rspStausObj.value("ErrorCode").toString();
		rspStatus.errorMsg = rspStausObj.value("ErrorMsg").toString();
		rspStatus.isSuccess = rspStausObj.value("IsSuccess").toBool();
		QJsonObject inferenceTimeObj = rspStausObj.value("InferenceTime").toObject();
		if (!inferenceTimeObj.isEmpty())
		{
			rspStatus.inferenceTime.all = inferenceTimeObj.value("All").toDouble();
			rspStatus.inferenceTime.postAI = inferenceTimeObj.value("PostAI").toDouble();
			rspStatus.inferenceTime.stream = inferenceTimeObj.value("Stream").toDouble();
		}

		QList<DetPlusDetClassification> detPlusDetClsList;
		QList<DetPlusOcr> detPlusOcrList;
		QList<DetPlusSeg> detPlusSegList;
		switch (sceneTag)
		{
		case SceneTag::DET_PLUS_DET:
			qInfo() << "parse rsp, scene tag:" << STR_DET_DET_SCENE_NAME;
			//TODO: need to complete logic 
			break;
		case SceneTag::DET_PLUS_DET_CLS:
			qInfo() << "parse rsp, scene tag:" << STR_DET_DET_CLS_SCENE_NAME;
			// parse DetPlusDetCls List
			this->parseDetDetClsList(resultArray, detPlusDetClsList, listLen);
			detPlusRsp.detClsRspMap.insert(fileName, detPlusDetClsList);
			break;
		case SceneTag::DET_PLUS_OCR:
			qInfo() << "parse rsp, scene tag:" << STR_DET_OCR_SCENE_NAME;
			// parse DetPlusOcr List
			this->parseDetOcrList(resultArray, detPlusOcrList, listLen);
			detPlusRsp.ocrRspMap.insert(fileName, detPlusOcrList);
			break;
		case SceneTag::DET_PLUS_SEG:
			qInfo() << "parse rsp, scene tag:" << STR_DET_SEG_SCENE_NAME;
			// parse DetPlusOcr List
			this->parseDetSegList(resultArray, detPlusSegList, listLen);
			detPlusRsp.segRspMap.insert(fileName, detPlusSegList);
			break;
		default:
			qCritical() << "not implemented scene tag.";
			retCode = -1;
		}
	}
	return retCode;
}

QString DetPlusRsp::toString()
{
	QString detClsStr;
	QMapIterator<QString, QList<DetPlusDetClassification>> iter1(this->detClsRspMap);
	while (iter1.hasNext())
	{
		iter1.next();
		detClsStr.append(iter1.key()).append(",  ");
		QList<DetPlusDetClassification> clss = iter1.value();
		if (!clss.isEmpty()) {
			for each (DetPlusDetClassification obj in clss)
			{
				detClsStr.append(obj.classification.label)
					.append(";  ");
			}
		}
	}

	QString ocrStr;
	QMapIterator<QString, QList<DetPlusOcr>> iter2(this->ocrRspMap);
	while (iter2.hasNext())
	{
		iter2.next();
		ocrStr.append(iter2.key()).append(",  ");
		QList<DetPlusOcr> ocrs = iter2.value();
		if (!ocrs.isEmpty()) {
			for each (DetPlusOcr obj in ocrs)
			{
				ocrStr.append(obj.ocr.ocrText.toLocal8Bit().constData())
					.append(";  ");
			}
		}
	}

	QString segStr;
	QMapIterator<QString, QList<DetPlusSeg>> iter3(this->segRspMap);
	while (iter3.hasNext())
	{
		iter3.next();
		segStr.append(iter3.key()).append(",  ");
		QList<DetPlusSeg> segs = iter3.value();
		if (!segs.isEmpty()) {
			for each (DetPlusSeg obj in segs)
			{
				segStr.append(obj.segmentation.codeType)
					.append(",  ")
					.append(QString::number(obj.segmentation.score))
					.append(";  ");
			}
		}
	}

	return QString("errorCode:%1\terrorMsg:%2 \tIsSuccess:%3 \
			\tdetClsRspMap:%4 \tocrRspMap:%5  \tsegRsp:%6")
		.arg(this->rspStatus.errorCode)
		.arg(this->rspStatus.errorMsg)
		.arg(this->rspStatus.isSuccess)
		.arg(detClsStr)
		.arg(ocrStr)
		.arg(segStr);
}
